package com.smartfast4j.common.filter;

import com.smartfast4j.common.util.AesEncryptUtils;
import com.smartfast4j.common.util.RSAUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.IOException;
import java.util.*;

/**
 * 请求参数过滤器
 * Created by gacl on 2017/9/13.
 */
public class ParameterFilter implements Filter {

    private static final Logger logger = LoggerFactory.getLogger(ParameterFilter.class);

    private Set<String> prefixIgnores = new HashSet<>();

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        String cp = filterConfig.getServletContext().getContextPath();
        String ignoresParam = filterConfig.getInitParameter("ignores");
        if(StringUtils.isNotEmpty(ignoresParam)){
            String[] ignoreArray = ignoresParam.split(",");
            for (String s : ignoreArray) {
                prefixIgnores.add(cp + s);
            }
        }

    }

    @Override
    public void destroy() {
        prefixIgnores = null;
    }

    private boolean canIgnore(HttpServletRequest request) {
        String url = request.getRequestURI();
        for (String ignore : prefixIgnores) {
            if (url.startsWith(ignore)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain) throws IOException, ServletException {
        logger.debug("ParameterFilter→拦截请求参数");
        HttpServletRequest request = (HttpServletRequest)req;
        String reqUrl = request.getRequestURL().toString();
        logger.debug("ParameterFilter→访问的URL："+reqUrl);
        if (canIgnore(request)) {
            logger.debug("访问的URL："+reqUrl+"是可以忽略的URL");
            filterChain.doFilter(req, res);
            return;
        }
        String ajaxRequest = request.getParameter("ajaxRequest");
        //不是ajax请求
        if(!"yes".equals(ajaxRequest)){
            filterChain.doFilter(req, res);
            return;
        }
        Map<String,String[]> parameterMap = new HashMap<>(req.getParameterMap());
        Map<String,String[]> newParameterMap = new HashMap<>(req.getParameterMap());
        String aesKey = "";//AES解密密钥
        if(parameterMap.containsKey("aesKey")){
            //解密
            aesKey = RSAUtils.decryptStringByJs(parameterMap.get("aesKey")[0]);
            System.out.println("使用RSA解密后的aesKey="+aesKey);
            if(StringUtils.isEmpty(aesKey)){
                aesKey = parameterMap.get("aesKey")[0];
            }
            newParameterMap.put("aesKey", new String[]{aesKey});
        }
        for (Iterator<String> it = parameterMap.keySet().iterator(); it.hasNext();) {
            String name = it.next();
            String[] values = req.getParameterValues(name);
            System.out.println(name + "=");
            if (values != null) {
                for (int i = 0; i < values.length; i++) {
                    System.out.print(values[i] + ",");
                }
                try {
                    //进行AES解密
                    String decryptVal = AesEncryptUtils.aesDecrypt(values[0],aesKey);
                    System.out.print("进行AES解密，解密后的结果="+decryptVal);
                    newParameterMap.put(name,new String[]{decryptVal});
                } catch (Exception e) {
                    newParameterMap.put(name, values);
                }
            }
            System.out.println();
        }
        req = new ParameterRequestWrapper((HttpServletRequest)req, newParameterMap);

        filterChain.doFilter(req, res);
    }

    class ParameterRequestWrapper extends HttpServletRequestWrapper {

        private Map<String, String[]> params;

        public ParameterRequestWrapper(HttpServletRequest request, Map<String, String[]> newParams) {
            super(request);
            this.params = newParams;
            // RequestDispatcher.forward parameter
            renewParameterMap(request);
        }

        @Override
        public String getParameter(String name) {
            String result = "";

            Object v = params.get(name);
            if (v == null) {
                result = null;
            } else if (v instanceof String[]) {
                String[] strArr = (String[]) v;
                if (strArr.length > 0) {
                    result =  strArr[0];
                } else {
                    result = null;
                }
            } else if (v instanceof String) {
                result = (String) v;
            } else {
                result =  v.toString();
            }

            return result;
        }

        @Override
        public Map getParameterMap() {
            return params;
        }

        @Override
        public Enumeration getParameterNames() {
            return new Vector(params.keySet()).elements();
        }

        @Override
        public String[] getParameterValues(String name) {
            String[] result = null;

            Object v = params.get(name);
            if (v == null) {
                result =  null;
            } else if (v instanceof String[]) {
                result =  (String[]) v;
            } else if (v instanceof String) {
                result =  new String[] { (String) v };
            } else {
                result =  new String[] { v.toString() };
            }

            return result;
        }

        private void renewParameterMap(HttpServletRequest req) {

            String queryString = req.getQueryString();

            if (queryString != null && queryString.trim().length() > 0) {
                String[] params = queryString.split("&");

                for (int i = 0; i < params.length; i++) {
                    int splitIndex = params[i].indexOf("=");
                    if (splitIndex == -1) {
                        continue;
                    }

                    String key = params[i].substring(0, splitIndex);

                    if (!this.params.containsKey(key)) {
                        if (splitIndex < params[i].length()) {
                            String value = params[i].substring(splitIndex + 1);
                            this.params.put(key, new String[] { value });
                        }
                    }
                }
            }
        }

    }
}
